package com.itesm.sistemasinteligentes.sat;

import java.util.Map;

import javax.swing.text.MutableAttributeSet;

public class GSAT extends SATSolver {
	/**/

	public GSAT(int[][] clauses, int maxFlips, int maxTries) {
		super(clauses, maxFlips, maxTries);
	}

	@Override
	public boolean solveImplementation() {
		flipsRequired = 0;
		for (int i = 1; i <= maxTries; i++) {
			setRandomSolutionValues();
			for (int j = 1; j <= maxFlips; j++) {
				if (isValidSolution()) {
					flipsInLastTry = j;
					triesRequired = i;
					flipsRequired += j;
					return true;
				}else if(stopThread){					
					return false;
				}
				changeGreedyValue();
			}
			flipsRequired += maxFlips;
		}
		return false;
	}

	private void changeGreedyValue() {
		int clausesValid = 0;
		Map.Entry<Integer, Boolean> maxEntry = null;
		int maxEntryClausesValid = 0;
		for (Map.Entry<Integer, Boolean> entry : variables.entrySet()) {
			if (maxEntry == null) {
				maxEntry = entry;
			}
			// Swap the actual variable
			entry.setValue(!entry.getValue());
			for (int i = 0; i < clauses.length; i++) {
				for (int j = 0; j < clauses[i].length; j++) {
					if ((clauses[i][j] > 0 && variables.get(Math
							.abs(clauses[i][j])))
							|| (clauses[i][j] < 0 && !variables.get(Math
									.abs(clauses[i][j])))) {
						clausesValid++;
						break;
					}
				}
			}
			// Swap the actual variable
			entry.setValue(!entry.getValue());
			if (clausesValid > maxEntryClausesValid) {
				maxEntry = entry;
				maxEntryClausesValid = clausesValid;
			}else if(clausesValid == maxEntryClausesValid){
				if(Math.random()*10 > 5){
					maxEntry = entry;
					maxEntryClausesValid = clausesValid;
				}
			}
			clausesValid = 0;
		}
		// Swap the max greedy variable
		maxEntry.setValue(!maxEntry.getValue());
	}

	@Override
	public String report() {
		StringBuffer buffer = new StringBuffer();
		buffer.append("La solución encontrada utilizando GSAT es:\n");
		buffer.append("********************************************\n");
		buffer.append("Variable\t\tValor de Verdad\n");
		buffer.append("********************************************\n");
		for (Map.Entry<Integer, Boolean> entry : variables.entrySet()) {
			buffer.append(entry.getKey() + "\t\t\t" + entry.getValue() + "\n");
		}
		buffer.append("********************************************\n\n\n");
		buffer.append("Se requirieron " + triesRequired
				+ " intentos para obtener la solución.\n");
		buffer.append("Se requirieron " + flipsRequired
				+ " flips para obtener la solución.\n");
		buffer.append("Se requirieron unicamente " + flipsInLastTry
				+ " flips en el intento exitoso.\n");
		buffer.append("La ejecución duró " + (endTime - startTime)
				+ " milisegundos.\n");
		return buffer.toString();
	}

}
